using System;
using System.Configuration;
using System.Diagnostics;
using System.Net;
using System.Security.Permissions;
using System.Text.RegularExpressions;
using System.Web;
using System.Xml;
using HelpdeskServices.CrmWebReference;
using HelpdeskServices.KmsWebReference;
using HelpdeskServices.Properties;

/// <summary>
/// Singleton applied, in order to make sure that it is thread safe.
/// <list type="bullet">
///     <item>Decorated class, with minimum permissions required in order to run this class, the permission is required by <see cref="getConfigurationFilePath"/>
/// </item>
/// </list>
/// </summary>
[AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Medium)]
public sealed class Common
{
    private static readonly object syncRoot = new object();
    private static volatile Common instance;

    private Common()
    {
    }

    public static Common Instance
    {
        get
        {
            if (instance == null)
            {
                lock (syncRoot)
                {
                    if (instance == null)
                    {
                        instance = new Common();
                    }
                }
            }
            return instance;
        }
    }

    /// <summary>
    /// Removes the HTML tags.
    /// Removes comments
    /// Removes DOCTYPE's
    /// Configured from the resources files, so if there is any HTML tags that slips through you can add it in the resource file
    /// </summary>
    /// <param name="input">The input.</param>
    /// <returns></returns>
    public static string removeHTMLTags(string input)
    {
        return Regex.Replace(input, "<(.|\n)*?>", "");
    }

    /// <summary>
    /// Finds the order number in email body.
    /// </summary>
    /// <param name="emailBodyToParse">The email body to parse.</param>
    /// <returns></returns>
    public static int findOrderNumberInEmailBody(string emailBodyToParse)
    {
        int orderNumber;
        string orderNumberInString =
            Regex.Match(emailBodyToParse, Resources.RegularExpresionToExtractOrderNumber).ToString();
        int.TryParse(orderNumberInString, out orderNumber);
        return orderNumber;
    }
    /// <summary>
    /// Updates the config file, if the key that you are updating is within the appSettings section.
    /// It also refreshes the AppSetting Cache so that the applied setting, is availible in your web application.
    /// The keys needs to have been created within the config file before hand, but it could be empty.  example of an
    /// application key, that will be able to be set.
    /// <code>
    /// <add key="SupportQueueId" value=""/>
    /// </code>
    /// </summary>
    /// <param name="key">The key</param>
    /// <param name="value">The value</param>
    public static void UpdateConfigurationFile(string key, string value)
    {
        string configurationFile = getConfigurationFilePath();
        XmlDocument xmldoc = new XmlDocument();
        if (configurationFile == null)
        {
            throw new ConfigurationErrorsException(Resources.ConfigurationErrorFileNotFound);
        }

        xmldoc.Load(configurationFile);
        XmlNode node = xmldoc.DocumentElement.SelectSingleNode("//appSettings//add[@key='" + key + "']");

        if ((node.Attributes[1].Value)!= null)
        {
            node.Attributes[1].Value = value;
            xmldoc.Save(configurationFile);
        }

        //update the cached setting
        ConfigurationManager.AppSettings.Set(key, value);
    }
    private static string getConfigurationFilePath()
    {
        string configFileLocation;
        if (HttpContext.Current.Request.PhysicalApplicationPath != null)
        {
            configFileLocation = string.Concat(HttpContext.Current.Request.PhysicalApplicationPath, Resources.ConfigurationFile);
        }
        else
        {
            throw new ConfigurationErrorsException(Resources.ConfigurationErrorHttpContextNotFound);
        }
        return configFileLocation;
    }
    /// <summary>
    /// Write exceptions to the event logs.
    /// The most usefull information is within the InnerException, if Crm had a problem with the web request.  Other than that, all errors are unexpected.
    /// Examples of potential errors that might originate from CRM, is if somebody is trying to import a email, that another person has deleted just before
    /// the import is executed.
    ///
    /// </summary>
    public static void LogErrorMessage(Exception errorHandler)
    {
        if (!EventLog.SourceExists(AppDomain.CurrentDomain.FriendlyName))
        {
            EventLog.CreateEventSource(AppDomain.CurrentDomain.FriendlyName, Resources.DestinationEventLog);
        }

        EventLog myLog = new EventLog();
        myLog.Source = AppDomain.CurrentDomain.FriendlyName;
        try
        {
            myLog.WriteEntry(errorHandler.InnerException.Data.ToString(), EventLogEntryType.Error);
        }
        catch (NullReferenceException)
        {
            myLog.WriteEntry(errorHandler.Message, EventLogEntryType.Warning);
        }
    }
    /// <summary>
    /// Creates credentials based on settings in the web.config
    /// If UseIntegratedAuthentication is set to false, it use the configured ServiceAccount Settings.  This is mainly for debugging
    /// and by not using integrated authentication, all the action's and records that the system has a effect on will be owned by the configured user.
    /// When using integrated authentication, records will be owned by user, executing function. 
    /// </summary>
    /// <returns></returns>
    private static NetworkCredential getNetworkCredential()
    {
        NetworkCredential credential;

        if (ConfigurationManager.AppSettings[Resources.ConfigurationKeyForIntegratedAuthentication].ToLower().Contains("true"))
        {
            credential = CredentialCache.DefaultNetworkCredentials;
        }
        else
        {
            string userName = ConfigurationManager.AppSettings[Resources.ConfigurationKeyForServiceAccountUserName];
            string password = ConfigurationManager.AppSettings[Resources.ConfigurationKeyForServiceAccountPassword];
            string domain = ConfigurationManager.AppSettings[Resources.ConfigurationKeyForServiceAccountDomain];

            credential = new NetworkCredential(userName, password, domain);
        }
        return credential;
    }
    /// <summary>
    /// The webservice proxy, had to be overriden, in order to enable multiple calls to the web serivce, to not drop the connection and
    /// impacting a diffrent thread, that might be waiting for the results.  It fails with a error message
    /// </summary>
    /// <returns></returns>
    /// <seealso cref="WebServiceKeptAlive"/>
    public static CrmService CrmWebServiceProxy()
    {
        CrmService service = new WebServiceKeptAlive();
        service.Credentials = getNetworkCredential();

        return service;
    }
    /// <summary>
    /// Creates the Authorizations header for the KMS Search Service.
    /// This has been changed, and no longer require the password, but it does require
    /// the 
    /// </summary>
    /// <returns></returns>
    private static AuthHeader CreateKalahariManagmentSystemWebServiceProxyAuthorizationHeader()
    {
        AuthHeader header = new AuthHeader();
        header.Username = ConfigurationManager.AppSettings["KalHeader.Username"];
        header.Password = ConfigurationManager.AppSettings["KalHeader.Password"];
        return header;
    }
    /// <summary>
    /// Creates the security and configuring the credentials for use with the KMS web services
    /// </summary>
    /// <remarks>
    /// </remarks>
    /// <returns></returns>
    public static CRMService KalahariManagmentSystemWebServiceProxy()
    {
        CRMService service = new CRMService();
        service.Credentials = getNetworkCredential();
        service.AuthHeaderValue = CreateKalahariManagmentSystemWebServiceProxyAuthorizationHeader();

        return service;
    }
}